package com.yugao.fintech.antelope.base.config.core;

import com.alibaba.fastjson2.JSON;
import com.yugao.fintech.antelope.base.config.core.event.ConfigDeleteEvent;
import com.yugao.fintech.antelope.base.config.core.event.ConfigRefreshEvent;
import com.yugao.fintech.antelope.base.config.remote.ConfigManageApi;
import com.yugao.fintech.antelope.base.model.enums.ConfigDefineEnum;
import com.yugao.fintech.antelope.base.model.enums.ConfigKeyEnum;
import com.yugao.fintech.antelope.base.model.module.config.ConfigInfo;
import com.yugao.fintech.antelope.base.model.module.tenant.TenantContextHolder;
import com.yugao.fintech.framework.assistant.utils.exception.BizException;
import com.yugao.fintech.framework.core.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 配置工厂
 */
@Slf4j
@Component
public class ConfigFactory {
    /**
     * 当前服务监听的配置
     */
    private static final Set<String> LISTEN_CONFIG = new HashSet<>();

    /**
     * key: tenant_id:config_key
     */
    protected static final Map<String, ConfigInfo> configMap = new ConcurrentHashMap<>();

    @Autowired
    @Lazy
    private ConfigManageApi configManageApi;

    @PostConstruct
    public void init() {

    }

    protected String getCacheKey(ConfigDefineEnum configDefine) {
        return TenantContextHolder.get().getTenantId() + ":" + configDefine.name();
    }

    protected void deleteConfig(ConfigKeyEnum configKey) {
        ConfigDefineEnum configDefine = ConfigDefineEnum.ofByKey(configKey);
        String cacheKey = getCacheKey(configDefine);
        configMap.remove(cacheKey);
        SpringUtils.getContext().publishEvent(new ConfigDeleteEvent(configKey.getKey()));
    }

    public boolean hasConfig(ConfigDefineEnum configDefine) {
        return configMap.containsKey(getCacheKey(configDefine));
    }

    public ConfigInfo getConfigOfNonNull(ConfigDefineEnum configDefine) {
        return getConfig(configDefine, true);
    }

    public ConfigInfo getConfig(ConfigDefineEnum configDefine) {
        return getConfig(configDefine, false);
    }

    private ConfigInfo getConfig(ConfigDefineEnum configDefine, boolean requestNonNull) {
        String errorMsg = "尚未配置或者使能参数, 请到设置中心检查配置";
        String cacheKey = getCacheKey(configDefine);
        initPublicConfig();

        ConfigInfo configInfo = configMap.get(cacheKey);
        if (Objects.isNull(configInfo)) {
            synchronized (cacheKey.intern()) {
                configInfo = configMap.get(cacheKey);
                if (Objects.nonNull(configInfo)) {
                    return configInfo;
                }
                try {
                    configInfo = configManageApi.getUseConfig(configDefine).get();
                } catch (Exception e) {
                    throw new BizException("获取配置失败");
                }
                log.warn("初始化租户 {} 的 {} 配置, config: {}", TenantContextHolder.get().getTenantId(), configDefine.name(), JSON.toJSONString(configInfo));
                if (Objects.isNull(configInfo)) {
                    log.error("tenantId: {}, error: {}", TenantContextHolder.get().getTenantId(), errorMsg);
                    if (requestNonNull) {
                        throw new BizException(errorMsg);
                    }
                    return null;
                }
                configMap.put(cacheKey, configInfo);
            }
        }
        return configInfo;
    }

    /**
     * 初始化公共配置
     */
    private void initPublicConfig() {
        String cacheKey = getCacheKey(ConfigDefineEnum.WEB_SITE);
        ConfigInfo configInfo = configMap.get(cacheKey);
        if (Objects.isNull(configInfo)) {
            synchronized (cacheKey.intern()) {
                configInfo = configMap.get(cacheKey);
                if (Objects.nonNull(configInfo)) {
                    return;
                }
                try {
                    configInfo = configManageApi.getUseConfig(ConfigDefineEnum.WEB_SITE).get();
                    if (Objects.isNull(configInfo)) {
                        log.error("配置不存在, cacheKey: {}", cacheKey);
                        throw new BizException("公共配置不存在");
                    }
                } catch (Exception e) {
                    if (e instanceof BizException) {
                        throw (BizException) e;
                    }
                    log.error("error: ", e);
                    throw new BizException("获取公共配置失败");
                }
                configMap.put(cacheKey, configInfo);
            }
        }
    }

    public void refreshConfig(ConfigMsg payload) {
        String cacheKey = getCacheKey(ConfigDefineEnum.ofByKey(payload.getConfigKey()));
        synchronized (cacheKey.intern()) {
            ConfigInfo configInfo = new ConfigInfo();
            configInfo.setTenantId(payload.getTenantId());
            configInfo.setConfigValue(payload.getConfigValue());
            configInfo.setConfigKey(payload.getConfigKey());
            configMap.put(cacheKey, configInfo);
            SpringUtils.getContext().publishEvent(new ConfigRefreshEvent(configInfo));
        }
    }

    public static void addListenConfigs(ConfigDefineEnum... configDefineEnums) {
        for (ConfigDefineEnum item : configDefineEnums) {
            LISTEN_CONFIG.add(item.name());
        }
    }
}
